package io.finer.erp.jeecg.approve.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.finer.erp.jeecg.approve.entity.*;
import io.finer.erp.jeecg.approve.service.*;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.system.vo.LoginUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Type;
import java.util.*;

public class ApproveServiceImpl<M extends BaseMapper<T> ,T> extends ServiceImpl<M , T> implements ApproveService<T> {

    @Autowired
    ApproveFlowInstanceService approveFlowInstanceService;

    @Autowired
    ApproveFlowService approveFlowService;

    @Autowired
    ApproveFlowNodeService approveFlowNodeService;

    @Autowired
    ApproveMemberService approveMemberService;

    @Autowired
    ApproveRecordService approveRecordService;

    @Override
    @Transactional
    public void submit(String model, String id, IService<T> service) {
        ApproveFlowInstance approveFlowInstance = new ApproveFlowInstance();
        QueryWrapper<ApproveFlow> approveFlowQueryWrapper = new QueryWrapper<>();
        List<ApproveFlow> approveFlowList = approveFlowService.list(approveFlowQueryWrapper.eq("model", model));
        for(ApproveFlow approveFlow: approveFlowList){
            QueryWrapper<T> equeryWrapper = new QueryWrapper<>();
            if (approveFlow.getCondition() != null && StringUtils.isNotBlank(approveFlow.getCondition())){
                equeryWrapper.apply(approveFlow.getCondition());
            }
            equeryWrapper.eq("id", id);
            System.out.println(id);
            T entity = service.getOne(equeryWrapper);
            if(entity != null){
                System.out.println("获取到entity");
                approveFlowInstance.setApproveFlowId(approveFlow.getId());
                approveFlowInstance.setCurPos(0);
                approveFlowInstance.setModel(approveFlow.getModel());
                approveFlowInstance.setDocumentId(id);
                approveFlowInstance.setStatus("processing");
                approveFlowInstanceService.save(approveFlowInstance);
                System.out.println("创建instance");

                QueryWrapper<ApproveFlowNode> approveFlowNodeQueryWrapper = new QueryWrapper<>();
                List<ApproveFlowNode> approveFlowNodeList = approveFlowNodeService.list(approveFlowNodeQueryWrapper.eq("approve_flow_id", approveFlow.getId()));
                QueryWrapper<ApproveMember> approveMemberQueryWrapper = new QueryWrapper<>();
                for(ApproveFlowNode approveFlowNode: approveFlowNodeList){
                    approveMemberQueryWrapper.clear();
                    List<ApproveMember> approveMemberList = approveMemberService.
                            list(approveMemberQueryWrapper.eq("node_id", approveFlowNode.getId()));
                    ArrayList<ApproveRecord> approveRecords = new ArrayList<>();
                    for(ApproveMember approveMember: approveMemberList){
                        System.out.println("创建审批记录");
                        ApproveRecord approveRecord = new ApproveRecord();
                        approveRecord.setInstanceId(approveFlowInstance.getId());
                        approveRecord.setApproveMemberId(approveMember.getId());
                        approveRecord.setUserId(approveMember.getUserId());
                        approveRecords.add(approveRecord);
                    }
                    approveRecordService.saveBatch(approveRecords);
                }

            }
        }

    }

    @Override
    @Transactional
    public String approve(String model, String id, String note) {
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();

        QueryWrapper<ApproveFlowInstance> approveFlowInstanceQueryWrapper = new QueryWrapper<>();
        ApproveFlowInstance approveFlowInstance = approveFlowInstanceService.getOne(approveFlowInstanceQueryWrapper.eq("model", model)
                .eq("document_id", id));
        QueryWrapper<ApproveFlowNode> approveFlowNodeQueryWrapper = new QueryWrapper<>();
        ApproveFlowNode approveFlowNode = approveFlowNodeService.getOne(approveFlowNodeQueryWrapper.
                eq("approve_flow_id",approveFlowInstance.getApproveFlowId())
                .eq("pos",approveFlowInstance.getCurPos()));
        approveFlowNodeQueryWrapper.clear();
        ApproveFlowNode lastApproveFlowNode = approveFlowNodeService.getOne(approveFlowNodeQueryWrapper.
                eq("approve_flow_id",approveFlowInstance.getApproveFlowId())
                .eq("last",1));

        QueryWrapper<ApproveMember> approveMemberQueryWrapper = new QueryWrapper<>();
        QueryWrapper<ApproveRecord> approveRecordQueryWrapper = new QueryWrapper<>();

        ApproveMember approveMember = approveMemberService.getOne(approveMemberQueryWrapper.eq("node_id"
                , approveFlowNode.getId()).eq("user_id", sysUser.getUsername()));

        ApproveRecord approveRecord = approveRecordService.getOne(approveRecordQueryWrapper.
                eq("approve_member_id", approveMember.getId()).eq("instance_id", approveFlowInstance.getId()));

        approveRecord.setApproveResult("pass");
        approveRecord.setApproveTime(new Date());
        approveRecord.setNote(note);

        approveRecordService.updateById(approveRecord);

        List<ApproveMember> approveMemberList = approveMemberService.list(approveMemberQueryWrapper.eq("node_id"
                , approveFlowNode.getId()));

        ArrayList<Integer> memberIdList = new ArrayList<>();

        for (ApproveMember am: approveMemberList) {
            memberIdList.add(am.getId());
        }
        approveRecordQueryWrapper.clear();
        Integer passRecordCnt = approveRecordService.count(approveRecordQueryWrapper.in("approve_member_id"
                , memberIdList).eq("approve_result", "pass").eq("instance_id", approveFlowInstance.getId()));

        if (passRecordCnt == approveMemberList.size()){
            if(approveFlowInstance.getCurPos() == lastApproveFlowNode.getPos()){
                approveFlowInstance.setStatus("approve_complete");
            }else{
                approveFlowInstance.setCurPos(approveFlowInstance.getCurPos() + 1);
            }
            approveFlowInstanceService.updateById(approveFlowInstance);
        }
        return approveFlowInstance.getStatus();
    }

    @Override
    public boolean canApproveorReject(String model, String id) {
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        QueryWrapper<ApproveFlowInstance> approveFlowInstanceQueryWrapper = new QueryWrapper<>();
        ApproveFlowInstance approveFlowInstance = approveFlowInstanceService.getOne(approveFlowInstanceQueryWrapper.eq("model", model)
                .eq("document_id", id).ne("status","approve_complete").ne("status","approve_reject"));

        if (approveFlowInstance != null){
            QueryWrapper<ApproveFlowNode> approveFlowNodeQueryWrapper = new QueryWrapper<>();
            ApproveFlowNode approveFlowNode = approveFlowNodeService.getOne(approveFlowNodeQueryWrapper.
                    eq("approve_flow_id",approveFlowInstance.getApproveFlowId())
                    .eq("pos",approveFlowInstance.getCurPos()));

            QueryWrapper<ApproveMember> approveMemberQueryWrapper = new QueryWrapper<>();
            QueryWrapper<ApproveRecord> approveRecordQueryWrapper = new QueryWrapper<>();

            ApproveMember approveMember = approveMemberService.getOne(approveMemberQueryWrapper.eq("node_id"
                    , approveFlowNode.getId()).eq("user_id",sysUser.getUsername()));

            if (approveMember != null){
                ApproveRecord approveRecord = approveRecordService.getOne(approveRecordQueryWrapper.
                        eq("approve_member_id", approveMember.getId()).eq("instance_id", approveFlowInstance.getId()));
                if (approveRecord.getApproveResult() != "pass" || approveRecord.getApproveResult() != "reject"){
                    return true;
                }
            }
        }

        return false;
    }

    @Override
    public Map<String, Boolean> canSubmitorWithdraworInvalid(String model, String id, IService<T> service) {
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        HashMap<String, Boolean> res = new HashMap<String, Boolean>(){
            {
                put("canSubmit", false);
                put("canWithdraw", false);
                put("canInvalid", false);
            }
        };
        QueryWrapper<T> equeryWrapper = new QueryWrapper<>();
        equeryWrapper.eq("id", id).select("bill_proc_status", "create_by");
        List<Map<String, Object>> stateandCreated = service.listMaps(equeryWrapper);
        String status = "";
        String createBy = "";
        for(Map<String, Object> sc: stateandCreated){
            status = sc.getOrDefault("bill_proc_status", "").toString();
            createBy = sc.getOrDefault("create_by", "").toString();
            break;
        }
        if (createBy.equals(sysUser.getUsername())){
            if ("submit".equals(status) ){
                res.put("canWithdraw", true);
                return res;
            }
            if ("create".equals(status)){
                res.put("canSubmit", true);
                return res;
            }
            if ("reject".equals(status)){
                res.put("canInvalid", true);
                return res;
            }
        }

        return res;
    }

    @Override
    @Transactional
    public void reject(String model, String id, String note) {
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();

        QueryWrapper<ApproveFlowInstance> approveFlowInstanceQueryWrapper = new QueryWrapper<>();
        ApproveFlowInstance approveFlowInstance = approveFlowInstanceService.getOne(approveFlowInstanceQueryWrapper.eq("model", model)
                .eq("document_id", id));
        QueryWrapper<ApproveFlowNode> approveFlowNodeQueryWrapper = new QueryWrapper<>();
        ApproveFlowNode approveFlowNode = approveFlowNodeService.getOne(approveFlowNodeQueryWrapper.
                eq("approve_flow_id",approveFlowInstance.getApproveFlowId())
                .eq("pos",approveFlowInstance.getCurPos()));

        QueryWrapper<ApproveMember> approveMemberQueryWrapper = new QueryWrapper<>();
        QueryWrapper<ApproveRecord> approveRecordQueryWrapper = new QueryWrapper<>();

        ApproveMember approveMember = approveMemberService.getOne(approveMemberQueryWrapper.eq("node_id"
                , approveFlowNode.getId()).eq("user_id", sysUser.getUsername()));

        ApproveRecord approveRecord = approveRecordService.getOne(approveRecordQueryWrapper.
                eq("approve_member_id", approveMember.getId()).eq("instance_id", approveFlowInstance.getId()));

        approveRecord.setApproveResult("reject");
        approveRecord.setApproveTime(new Date());
        approveRecord.setNote(note);

        approveRecordService.updateById(approveRecord);

        approveFlowInstance.setStatus("approve_reject");

        approveFlowInstanceService.updateById(approveFlowInstance);

    }

    @Override
    public List<ApproveRecord> queryApproveRecordList(String model, String id) {
        QueryWrapper<ApproveFlowInstance> approveFlowInstanceQueryWrapper = new QueryWrapper<>();
        ApproveFlowInstance approveFlowInstance = approveFlowInstanceService.getOne(approveFlowInstanceQueryWrapper.eq("model", model)
                .eq("document_id", id));
        List<ApproveRecord> approveRecordList = null;
        if (approveFlowInstance != null){
            QueryWrapper<ApproveRecord> approveRecordQueryWrapper = new QueryWrapper<>();
            approveRecordList = approveRecordService.list(approveRecordQueryWrapper.eq("instance_id", approveFlowInstance.getId()));
        }
        return approveRecordList;
    }

    @Override
    @Transactional
    public void withDraw(String model, String id) {
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        QueryWrapper<ApproveFlowInstance> approveFlowInstanceQueryWrapper = new QueryWrapper<>();
        QueryWrapper<ApproveRecord> approveRecordQueryWrapper = new QueryWrapper<>();
        ApproveFlowInstance approveFlowInstance = approveFlowInstanceService.getOne(approveFlowInstanceQueryWrapper.eq("model", model)
                .eq("document_id", id));
        approveRecordService.remove(approveRecordQueryWrapper.eq("instance_id", approveFlowInstance.getId()));
        approveFlowInstanceService.removeById(approveFlowInstance.getId());
    }
}
